/**
 * 
 */
package com.ideeli.webextractor.service;

import static com.ideeli.webextractor.utils.Constants.BASE_URL;
import static com.ideeli.webextractor.utils.Constants.INGRAM_PASS;
import static com.ideeli.webextractor.utils.Constants.INGRAM_USER;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.ElementNotVisibleException;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

import com.ideeli.webextractor.context.StaticContext;
import com.ideeli.webextractor.domain.ProductDetail;
import com.ideeli.webextractor.domain.SkuVpn;
import com.ideeli.webextractor.exception.ProductSkipException;
import com.ideeli.webextractor.utils.Constants;
import com.ideeli.webextractor.utils.Utility;

/**
 * @author spaida
 *
 */
public class IngExtractorServiceImpl implements IngExtractorService{
	
	private static final Logger logger = Logger.getLogger(IngExtractorService.class);
	private static int exceptionTrials=0;
	private String threadName;
	
	private WebDriver driver;
//	private String baseUrl;
//	private StringBuffer verificationErrors = new StringBuffer();
	private Map<String,Integer> allSkuVpnsPidMap;
	private static int i;
//	private Properties ingramProps;
	private ExtractProductDetailService extractProdDetails;
	private List<ProductDetail> productDetailList;
	private Map<String,Integer> parsedSkuVpnsInstance;
	
	private ProductService productService;
	private CacheService cacheService;
	private PriceChangeService priceChangeService;
	private int currentPageNo=-1;
	
	private String licProdVal;


	public  IngExtractorServiceImpl() throws Exception
	{

//		ingramProps = new Properties();
//		ingramProps.load(new FileInputStream("prop/ingram.properties"));
		
		Properties jdbcProps= new Properties();
		jdbcProps.load(new FileInputStream("prop/jdbc.properties"));
		
		String jdbcUrl=(String)jdbcProps.get("jdbc.url");
		
		if(jdbcUrl.contains("192"))
			StaticContext.getStaticContext().setHomeRun(true);
		
		
//		allSkuVpnsList = new ArrayList<String>();
		productDetailList= new ArrayList<ProductDetail>();
		parsedSkuVpnsInstance= new HashMap<String,Integer>();
	}
	
	@Override
	public String call() throws Exception
	{
		extract();
		return "Finished " + threadName;
	}

	
	@Override
	public void extract() throws Exception {
		
		logger.warn("extract()");
		recursiveProcess();

	}


	private void recursiveProcess()
	{
		logger.warn("recursiveProcess()");
		try
		{
			initBrowser();
			process();
		}
		catch(Throwable e)
		{
			logger.error("Exception occured closing the driver:",e);
			exceptionTrials++;
			if(exceptionTrials<10)
			{
				driver.close();
				recursiveProcess();
			}
		}
		
	}


	private void process() throws Exception
	{
		logger.warn("process()");
		Thread.sleep(1000 * 2);
		logger.warn("prodcuct activate click..");
		driver.findElement(By.id("product-activate")).click();
		Thread.sleep(1000 * 2);
		driver.findElement(By.linkText("View All")).click();
//		driver.findElement(By.name("View All")).click();
		
		logger.warn("qtp_showHideFacetTrigger..");
		driver.findElement(By.cssSelector("#qtp_showHideFacetTrigger > div.arrow-container")).click();

		try
		{
			logger.warn("stock1..");
			driver.findElement(By.id("qtp_SelectedStatusValuesList")).click();

		} catch (Exception e)
		{
			logger.warn("Exception block..");
			logger.warn("stock2..");
			driver.findElement(By.id("qtp_SelectedStatusValuesList3")).click();

		}

		logger.warn("stock srch..");
		driver.findElement(By.id("qtp_facet_actions_btn")).click();
		Thread.sleep(1000 * 4);		
		logger.warn("List without images..");
		driver.findElement(By.linkText("List")).click();
		logger.warn("select 30..");
		new Select(driver.findElement(By.id("topPagingSelect"))).selectByVisibleText("30");
		driver.findElement(By.cssSelector("option[value=\"30\"]")).click();

		
		long timeMillis=System.currentTimeMillis();
		allSkuVpnsPidMap=cacheService.getAllSkuVpns(1);
		parsedSkuVpnsInstance=cacheService.getParsedSkuVpns(1);
		int time=(int)(System.currentTimeMillis()-timeMillis)/1000;
		logger.warn("loaded allSkuVPns in sec: "+time);
		logger.warn("total no of loaded allSkuVPns "+allSkuVpnsPidMap.size());
		
		if(time<5)
			Thread.sleep(1000 * (6-time));
		
		driver.findElement(By.id("topSortSelect")).click();
		
		logger.warn("high to low..");
		new Select(driver.findElement(By.id("topSortSelect"))).selectByVisibleText("Price, High to Low");
		driver.findElement(By.cssSelector("option[value=\"1\"]")).click();
		
		String lastPageNo=driver.findElement(By.id("lastpagelink")).getText();
		logger.warn("lastPageNO:"+lastPageNo);
		Thread.sleep(1000 * 4);
		if("BACK".equals(threadName))
		{
			
			logger.info("This is the last thread, click last.");
			driver.findElement(By.id("last")).click();
			if(currentPageNo!=-1)
			{
				int last=Integer.parseInt(lastPageNo.trim());
				for(i=last;i>=currentPageNo;i--)
				{
					Thread.sleep(3*1000);
					driver.findElement(By.id("prev")).click();
				}
					
			}
			else
			{
				currentPageNo=Integer.parseInt(lastPageNo.trim());
			}
			
		}
		else
		{
			if(currentPageNo!=-1)
			{
				for(i=1;i<=currentPageNo;i++)
				{
					Thread.sleep(3*1000);
					driver.findElement(By.id("next")).click();
				}
			}
			else
				currentPageNo=1;
		}
		
		Thread.sleep(1000 * 4);
		
		try
		{
			while (true)
			{
//				List<WebElement> topDetails = driver.findElements(By.className("top-details"));
				List<WebElement> topDetails = driver.findElements(By.className("single-result"));
				
				recurIterate(topDetails);
				Thread.sleep(1000 * 2);
				
				if("BACK".equals(threadName))
				{
					synchronized(cacheService)
					{
						logger.info("*************clicking.. prev..*****************pageNo:"+ --currentPageNo );
						int frontPageNo=cacheService.getFrontPageNo();
					
						if(frontPageNo>=currentPageNo)
							break;
					
						cacheService.UpdateBackPageNo(currentPageNo);
					}
					driver.findElement(By.id("prev")).click();
				}
				else
				{
					synchronized(cacheService)
					{
						logger.info("*************clicking.. next..*****************pageNo:"+ ++currentPageNo );
						int backPageNo=cacheService.getBackPageNo();
					
						if(backPageNo <=currentPageNo)
							break;
						cacheService.updateFrontPgNo(currentPageNo);
					}
					driver.findElement(By.id("next")).click();
				}
			
				Thread.sleep(1000 * 3);
			}
			
		} catch (NoSuchElementException nosuchele)
		{
			logger.warn("NoSuchElementException");
			logger.warn("All links visited!!");
		}
		
//		printProductDetail();

	/*	while (true)
		{
			Thread.sleep(1000 * 60);
		}*/
		
		driver.close();
		
	}


	private void recurIterate(List<WebElement> topDetails) throws Exception
	{

		for (WebElement prodDetail : topDetails)
		{
			String prodDetailStr = prodDetail.getText();
			
			
			if(prodDetailStr!=null && prodDetailStr.contains(Constants.LICENCE_PRODUCT))
			{
				if(Constants.LICENCE_PRODUCT_SKIP.equals(licProdVal))
				{
					logger.info("skip the licence products");
					continue;//skip the licence products
				}
				else
				{
					logger.info("Include both licence and normal products");
				}
			}
			else if(prodDetailStr!=null && Constants.LICENCE_PRODUCT_EXCLUSIVE.equals(licProdVal))
			{
				logger.info("skip the products which are not Licence available");
				continue;//skip the products which are not Licence available;
			}
			
			if(prodDetailStr==null || !prodDetailStr.contains(Constants.IN_STOCK))
			{
				logger.info("Not in Stock.. skip");
				continue;
			}


			logger.debug("Product Detail  : "  + prodDetailStr);
			SkuVpn skuVpn = Utility.extractSKU(prodDetailStr);
			
			

			//if not sku model no is not present insert it else see else part
			if (!allSkuVpnsPidMap.containsKey(skuVpn.toString()))
			{
				i++;


//				WebElement clickProd = prodDetail.findElement(By.className("tooltip-clickable"));
				WebElement clickProd = prodDetail.findElement(By.className("product-name"));
				
				
				if (Utility.isNull(clickProd.getText()))
				{
//					allSkuVpnsPidMap.put(skuVpn.toString(),-1);
//					parsedSkuVpnsInstance.put(skuVpn.toString(),-1);
					markProductParsed(null,skuVpn,prodDetailStr);
					
					continue;
				}
				
				logger.info("****Prod no : " + i);
				logger.info("clickProd  : " + clickProd.getText());
				
				try
				{
//					clickProd.click();
					driver.findElement(By.linkText(clickProd.getText().trim())).click();
				}
				catch(ElementNotVisibleException e)
				{
					logger.error("product skipped:"+skuVpn,e);
					markProductParsed(null,skuVpn,prodDetailStr);
					continue;
				}
				catch (NoSuchElementException e)
				{
					logger.error("product skipped:"+skuVpn,e);
					markProductParsed(null,skuVpn,prodDetailStr);
					continue;
				}
				
				
				Thread.sleep(1000 * 4);
				// **************************** CALL Extract Prod Details
				// Service class************************
				ProductDetail productDetail=null ;
				try{
					productDetail = extractProdDetails.extract(driver);
					productDetail.setSupplier("ingrammicro");
					productService.insertINGProduct(productDetail);
				
				}
				catch(ProductSkipException e)
				{
					logger.error("product skipped:"+skuVpn,e);
				}
				catch(NumberFormatException e)
				{
					logger.error("product skipped:"+skuVpn,e);
				}
				finally
				{
					markProductParsed(productDetail,skuVpn,prodDetailStr);
				}
				
				
//				below map for priting purpose
//				productDetailList.add(productDetail);
				
				
				Thread.sleep(1000 * 3);
				//after the product visit come back
				driver.navigate().back();
				Thread.sleep(1000 * 6);
				
				//after coming back refresh the top-details
				List<WebElement> topDetailsRec =driver.findElements(By.className("single-result"));
				 
//				if(i< 1)
					 recurIterate(topDetailsRec);
				
				
				break;
			}
			else
			{
				//else update product price only if it is not parsed within last 24 hours
				if(!parsedSkuVpnsInstance.containsKey(skuVpn.toString()))
				{
					//update the price
					try
					{
						float newBasePrice=parseBasePrice(prodDetailStr);
						Integer prodId=allSkuVpnsPidMap.get(skuVpn.toString());
						priceChangeService.updatePrice(newBasePrice,prodId);	
					}
					catch(Throwable e)
					{
						cacheService.addErrorToList("Price change unsuccessfull: "+prodDetailStr);
						cacheService.addErrorToList(e.toString());
					}
					
					parsedSkuVpnsInstance.put(skuVpn.toString(),-1);
					productService.markAsProductParsed(skuVpn.getSku(), skuVpn.getVpn(),"", prodDetailStr,-1);
				}
			}

		}

	}
	
	private void markProductParsed(ProductDetail productDetail,SkuVpn skuVpn,String prodDetailStr) throws Exception
	{
		int prodId=-1;
		if(productDetail!=null)
		{
			prodId=productDetail.getProductId();
		}
		allSkuVpnsPidMap.put(skuVpn.toString(),prodId);
		parsedSkuVpnsInstance.put(skuVpn.toString(),prodId);
		productService.markAsProductParsed(skuVpn.getSku(), skuVpn.getVpn(),"", prodDetailStr,prodId);
	}

	
	private float parseBasePrice(String prodDetailStr)
	{
		int bgIndex=prodDetailStr.lastIndexOf('$');
		int endIndex=prodDetailStr.lastIndexOf("GST");
		
		String yourPrice=prodDetailStr.substring(bgIndex, endIndex);
		
		String basePriceStr=Utility.extractPrice(yourPrice);
		float basePrice=Float.parseFloat(basePriceStr);
		return basePrice;
	}


	private void printProductDetail()
	{
		for(ProductDetail productDetail: productDetailList)
		{
			
			logger.debug(productDetail);
			logger.debug("\n*****info print*****\n");
			
			Utility.printMap(productDetail.getBaseProps());
			
			
			Utility.printMap(productDetail.getExtPropMap());
			
			for(String str: productDetail.getExtPropList())
			{
				logger.debug(str);
			}
			
		}
		
	}
	
	private void initBrowser() throws Exception
	{
		logger.warn("initBrowser()..");
		
		if("BACK".equals(threadName))
			Thread.sleep(8*1000);
		
		driver = new FirefoxDriver();
	
		String baseUrl = cacheService.getAppProperty(BASE_URL);

		driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
		

		logger.info("base url..");
//		driver.get(baseUrl + "/");
//	    driver.get(baseUrl + "/_layouts/CommerceServer/IM/Login.aspx");
		driver.get(baseUrl);
		logger.info("Send username..");
	    driver.findElement(By.id("ctl00_PlaceHolderMain_txtUserEmail")).clear();
	    driver.findElement(By.id("ctl00_PlaceHolderMain_txtUserEmail")).sendKeys(cacheService.getAppProperty(INGRAM_USER));
	    driver.findElement(By.id("ctl00_PlaceHolderMain_txtPassword")).clear();
	    driver.findElement(By.id("ctl00_PlaceHolderMain_txtPassword")).sendKeys(cacheService.getAppProperty(INGRAM_PASS));
	    driver.findElement(By.id("ctl00_PlaceHolderMain_btnLogin")).click();

	    /**Old login style
	    driver.findElement(By.cssSelector("a.show-create-login-popup.key-login-btn")).click();
//	    driver.findElement(By.id("username")).clear();
//	    driver.findElement(By.id("username")).sendKeys("ideeli");
//	    driver.findElement(By.id("password")).clear();
//	    driver.findElement(By.id("password")).sendKeys("Ingram33##");
		logger.info("Send username..");
//		driver.findElement(By.id("username")).click();
		driver.findElement(By.id("username")).clear();
		driver.findElement(By.id("username")).sendKeys(cacheService.getAppProperty(INGRAM_USER));
		logger.info("Send password..");
		driver.findElement(By.id("password")).clear();
		driver.findElement(By.id("password")).sendKeys(cacheService.getAppProperty(INGRAM_PASS));
		logger.info("click login..");
		driver.findElement(By.id("loginBtn")).click();
		 * */
		licProdVal=cacheService.getConfigMapValue(Constants.LICENCE_PRODUCT_VAL);
		logger.info("Licence product flag:"+licProdVal);

	}



/*
	private boolean isElementPresent(By by)
	{
		try
		{
			driver.findElement(by);
			return true;
		} catch (NoSuchElementException e)
		{
			return false;
		}
	}
	*/

	public ExtractProductDetailService getExtractProdDetails() {
		return extractProdDetails;
	}

	public void setExtractProdDetails(ExtractProductDetailService extractProdDetails) {
		this.extractProdDetails = extractProdDetails;
	}
	

	public ProductService getProductService()
	{
		return productService;
	}


	public void setProductService(ProductService productService)
	{
		this.productService = productService;
	}


	/**
	 * @return the cacheService
	 */
	public CacheService getCacheService() {
		return cacheService;
	}


	/**
	 * @param cacheService the cacheService to set
	 */
	public void setCacheService(CacheService cacheService) {
		this.cacheService = cacheService;
	}

	public PriceChangeService getPriceChangeService()
	{
		return priceChangeService;
	}

	public void setPriceChangeService(PriceChangeService priceChangeService)
	{
		this.priceChangeService = priceChangeService;
	}



	public String getThreadName()
	{
		return threadName;
	}

	public void setThreadName(String threadName)
	{
		this.threadName = threadName;
	}






}
